#include "CityForm.h"
#include "NavigationManager.h"
#include "OpennavUtils.h"

using namespace Osp::App;
using namespace Osp::Base;
using namespace Osp::Base::Collection;
using namespace Osp::Ui;
using namespace Osp::Ui::Controls;
using namespace Osp::Graphics;
using namespace Osp::Io;
using namespace Osp::Text;

CityForm::CityForm()
	: __pSearchService(null), __pMap(null), __pCurrentResult(null), __pLock(null), __currentCountryId(0) { }

result CityForm::Construct(OpennavSearchServiceProvider* searchService, OpennavMap* map) {
	Form::Construct(L"IDF_SELECT_CITY");
	__pSearchService = searchService;
	__pMap = map;
	return E_SUCCESS;
}

result CityForm::OnInitializing() {
	result r = E_SUCCESS;
	__pScrollPanel = static_cast<ScrollPanel *>(GetControl(L"IDC_SCROLLPANEL1", false));
	__pListCity = static_cast<SlidableList *>(GetControl(L"IDPC_LIST_CITY", true));
	if (__pListCity != null) {
		__pListCity->AddSlidableListEventListener(*this);
		__pListCity->AddCustomItemEventListener(*this);
	}
	__pSearchCity = static_cast<EditField *>(GetControl(L"IDPC_SEARCH_CITY", true));
	if (__pSearchCity != null) {
		__pSearchCity->AddTextEventListener(*this);
		__pSearchCity->AddActionEventListener(*this);
		__pSearchCity->SetOverlayKeypadCommandButton(COMMAND_BUTTON_POSITION_RIGHT, L"Close", ID_BUTTON_EDITFIELD_CLOSE);
	}
	__pCustomListItemFormat = new CustomListItemFormat();
	__pCustomListItemFormat->Construct();
	__pCustomListItemFormat->AddElement(CITY_NAME_ID, Osp::Graphics::Rectangle(10, 10, 460, 55), 40);
	__pCustomListItemFormat->AddElement(WHERE_CITY_NAME_ID, Osp::Graphics::Rectangle(10, 65, 460, 30), 25);
	__pCustomListItemFormat->AddElement(WHERE_REGION_NAME_ID, Osp::Graphics::Rectangle(10, 100, 460, 30), 25);
	SetSoftkeyActionId(SOFTKEY_1, ID_SOFTKEY_BACK);
	AddSoftkeyActionListener(SOFTKEY_1, *this);
	__pLock = new Mutex();
	__pLock->Create();
	return r;
}

result CityForm::OnTerminating() {
	result r = E_SUCCESS;
	delete __pCustomListItemFormat;
	delete __pLock;
	return r;
}

void CityForm::OnActionPerformed(const Osp::Ui::Control& source, int actionId) {
	switch (actionId) {
		case ID_BUTTON_EDITFIELD_CLOSE:
			{
				__pScrollPanel->CloseOverlayWindow();
				__pSearchCity->Draw();
				__pSearchCity->Show();
			}
			break;
		case ID_SOFTKEY_BACK:
			{
				Frame *pFrame = Application::GetInstance()->GetAppFrame()->GetFrame();
				NavigationManager *pNavManager = static_cast<NavigationManager *>(pFrame->GetControl(NavigationManager::FORM_MANAGER_NAME));
				if (pNavManager != null) {
					pNavManager->SendUserEvent(NavigationManager::REQUEST_ID_COUNTRY_FORM, null);
				}
			}
			break;
		default:
			break;
	}
}

void CityForm::OnTextValueChanged(const Osp::Ui::Control& source) {
	PerformSearch();
}

void CityForm::OnLoadToTopRequested(const Osp::Ui::Control &source, int index, int numItems)
{
	if (__pListCity != null) {
		__pLock->Acquire();
		for(int i = index; i > index - numItems; i--) {
			opennav::City city;
			__pCurrentResult->GetResult(i, city);
			String cityName;
			OpennavUtils::Convert(city.name, cityName);
			CustomListItem* pItem = new CustomListItem();
			pItem->Construct(135);
			pItem->SetItemFormat(*__pCustomListItemFormat);
			pItem->SetElement(CITY_NAME_ID, cityName);
			pItem->SetElement(WHERE_CITY_NAME_ID, GetWhereCity(city));
			pItem->SetElement(WHERE_REGION_NAME_ID, GetWhereRegion(city));
			__pListCity->LoadItemToTop(*pItem, city.city_id);
		}
		__pLock->Release();
	}
}

void CityForm::OnLoadToBottomRequested (const Osp::Ui::Control &source, int index, int numItems)
{
	if (__pListCity != null) {
		__pLock->Acquire();
		for(int i = index; i < index + numItems; i++) {
			opennav::City city;
			__pCurrentResult->GetResult(i, city);
			String cityName;
			OpennavUtils::Convert(city.name, cityName);
			CustomListItem* pItem = new CustomListItem();
			pItem->Construct(135);
			pItem->SetItemFormat(*__pCustomListItemFormat);
			pItem->SetElement(CITY_NAME_ID, cityName);
			pItem->SetElement(WHERE_CITY_NAME_ID, GetWhereCity(city));
			pItem->SetElement(WHERE_REGION_NAME_ID, GetWhereRegion(city));
			__pListCity->LoadItemToBottom(*pItem, city.city_id);
		}
		__pLock->Release();
	}
}

void CityForm::OnItemStateChanged(const Osp::Ui::Control &source, int index, int itemId, Osp::Ui::ItemStatus status) {
	Frame *pFrame = Application::GetInstance()->GetAppFrame()->GetFrame();
	NavigationManager *pNavManager = static_cast<NavigationManager *>(pFrame->GetControl(NavigationManager::FORM_MANAGER_NAME));
	if (pNavManager != null) {
		ArrayList* args = new ArrayList();
		args->Construct();
		args->Add(*(new Integer(itemId)));
		pNavManager->SendUserEvent(NavigationManager::REQUEST_ID_ADDRESS_STREET_BY_CITY, args);
	}
}

void CityForm::OnUserEventReceivedN(RequestId requestId, IList* pArgs) {
	switch(requestId)
	{
		case REQUEST_ID_SET_COUNTRY:
			{
				__currentCountryId = ((Integer*)pArgs->GetAt(0))->ToInt();
				__pSearchCity->SetText(Osp::Base::String(""));
				PerformSearch();
			}
			break;
		default:
			break;
	}
}

void CityForm::OnGeocodingRequestResultReceived(IOpennavSearchResult* result) {
	AppLogDebug("search city request callback");
	if (result->GetRequestType() == SEARCH_CITY) {
		if (__pCurrentResult != null) {
			delete __pCurrentResult;
		}
		__pCurrentResult = (OpennavSearchCityResult*)result;
		__pListCity->RemoveAllItems();
		__pListCity->SetItemCountAndHeight(__pCurrentResult->GetCount(), __pCurrentResult->GetCount() * 135);
		__pListCity->Draw();
		__pListCity->Show();
		RequestRedraw(true);
	}
}

void CityForm::PerformSearch() {
	String text = __pSearchCity->GetText();
	__pLock->Acquire();
	__pListCity->RemoveAllItems();
	if (__pCurrentResult != null) {
		delete __pCurrentResult;
		__pCurrentResult = null;
	}
	__pListCity->SetItemCountAndHeight(0, 0);
	__pLock->Release();
	OpennavSearchCityRequest request = OpennavSearchCityRequest(text, __currentCountryId);
	__pSearchService->Search(request, *this);
}

Osp::Base::String CityForm::GetWhereRegion(opennav::City& city) {
	Osp::Base::String result;
	bool first = true;
	Region currentRegion;
	__pMap->GetRegion(city.region_id, currentRegion);
	while (true) {
		if (!first) {
			result.Append(L", ");
		}
		first = false;
		Osp::Base::String regionName;
		OpennavUtils::Convert(currentRegion.name, regionName);
		result.Append(regionName);
		if (currentRegion.parent_region_id < 0)
			break;
		__pMap->GetRegion(currentRegion.parent_region_id, currentRegion);
	}
	return result;
}

Osp::Base::String CityForm::GetWhereCity(opennav::City& city) {
	Osp::Base::String result;
	bool first = true;
	City currentCity = city;
	while (currentCity.parent_city_id >= 0) {
		__pMap->GetCity(currentCity.parent_city_id, currentCity);
		if (!first) {
			result.Append(L", ");
		}
		first = false;
		Osp::Base::String cityName;
		OpennavUtils::Convert(currentCity.name, cityName);
		result.Append(cityName);
	}
	return result;
}
